import os

import bpy

from ..ops.asset import ClearAsset
from .ui_list import AssetTree, SelectedSet
from ..utils.preferences import AddonProperty
from ..ops import render, asset, SHOW_DOCS


def _get_blender_icon(icon_style):
    """反回图标名称

    Args:
        icon_style (类型或直接输入两个已设置的图标, optional): 图标风格,也可以自已设置图标id. Defaults to 'TRIA' | 'ARROW' | 'TRI' | (str, str).
    Returns:
        (str,str): _description_
    """
    icon_data = {
        'TRI': ('DISCLOSURE_TRI_DOWN', 'DISCLOSURE_TRI_RIGHT'),
        'TRIA': ('TRIA_DOWN', 'TRIA_RIGHT'),
        'SORT': ('SORT_ASC', 'SORT_DESC'),
        'ARROW': ('DOWNARROW_HLT', 'RIGHTARROW'),
        'CHECKBOX': ('CHECKBOX_HLT', 'CHECKBOX_DEHLT'),
        'RESTRICT_SELECT': ('RESTRICT_SELECT_OFF', 'RESTRICT_SELECT_ON'),
        'FAKE': ('FAKE_USER_OFF', 'FAKE_USER_ON'),
    }
    if icon_style in icon_data:
        return icon_data[icon_style]
    else:
        return icon_data['TRI']


def icon_two(bool_prop, style='CHECKBOX', custom_icon: tuple[str, str] = None, ) -> str:
    """输入一个布尔值,反回图标类型str
    Args:
        bool_prop (_type_): _description_
        custom_icon (tuple[str, str], optional): 输入两个自定义的图标名称,True反回前者. Defaults to None.
        style (str, optional): 图标的风格. Defaults to 'CHECKBOX'.
    Returns:
        str: 反回图标str
    """
    icon_true, icon_false = custom_icon if custom_icon else _get_blender_icon(
        style)
    return icon_true if bool_prop else icon_false


def prefs():
    """反回插件属性
    """
    from ..utils.preferences import Preferences
    return Preferences.pref_()


def path_is_valid():
    """反回路径是否有效的布尔值
    需要资产有数量并且物体有数量
    """
    pref = prefs()
    valid_dir = os.path.isdir(pref.asset_root_path)
    valid_object = len(pref.asset_items_pointer_.asset_object_items)
    valid_scene = len(pref.asset_items_pointer_.asset_scene_items)
    return valid_scene and valid_object and valid_dir


def draw_path(layout: "bpy.types.UiLayout"):
    pref = prefs()

    row = layout.row()
    row.alert = not os.path.isdir(pref.asset_root_path)
    row.prop(pref, "asset_root_path")

    AssetLayout.load_asset(layout)
    layout.operator(ClearAsset.bl_idname)


class Queue:
    """
    绘制创建队列的
    包括池和其它两种添加队列的方式
    """
    layout: 'bpy.types.UILayout'

    @staticmethod
    def draw_queue_asset(layout: 'bpy.types.UILayout'):
        """绘制资产池内容"""
        col = layout.column()
        Queue.draw_queue_scene(col)
        Queue.draw_queue_object(col)

    @staticmethod
    def draw_grid_column() -> int:
        return bpy.context.area.width // 256

    @staticmethod
    def draw_queue_scene(layout: 'bpy.types.UILayout'):
        pref = prefs()

        selected_scene = pref.get_selected_assets('scene')
        left = layout.column()
        if selected_scene:
            left.label(text=f'已选择{len(selected_scene)}个场景')
            col = Queue.draw_grid_column()
            left_grid = left.grid_flow(
                row_major=True, columns=col,
            )
            for scene in selected_scene:
                scene.draw(left_grid)
        else:
            left.label(text='未选择场景')
            left.label(text='至少需选择一个场景')

    @staticmethod
    def draw_queue_object(layout: 'bpy.types.UILayout'):
        pref = prefs()
        object_assets = pref.get_selected_assets('object')
        right = layout.column()

        right.label(text=f'已选择{len(object_assets)}个产品')
        if len(object_assets) <= 1:
            row = right.row()
            row.alert = True
            row.label(text='至少需选择两个产品,如果只需要一个产品请切换至物体模式')
        col = Queue.draw_grid_column()
        right_grid = right.grid_flow(row_major=True,
                                     columns=col,
                                     )

        for scene in object_assets:
            scene.draw(right_grid)

    @staticmethod
    def draw_queue_left_export_info(layout: 'bpy.types.UILayout'):
        """不是资产模式并且设置为了渲染列表则显示
        """

        pref = prefs()
        if (not pref.is_asset_mode) and pref.is_show_render_queue:

            col = layout.column(align=True)
            col.separator(factor=3)

            co = col.column()
            # 总渲染次数和渲染时间

            if pref.is_scene_mode:
                # 显示输出文件数量
                co.prop(pref, 'export_assign_file_count')
            AssetLayout.draw_out_file_path(layout)

            co.separator(factor=3)

            bo = co.column(heading='预估导出信息', align=True)
            bo.label(text='预估导出信息', icon='FILE_BACKUP')
            box = bo.box()
            box.label(text='导出时主进程将会无响应')
            la = box.row()
            la.alert = not bpy.data.is_saved
            la.label(text='建议先保存文件!')

            sp = box.split(factor=0.2)

            sp.column()

            c = sp.column()

            c.label(text=f'输出文件数量:\t{pref.estimated_export_count}')
            c.label(text=f'总大小:\t{pref.estimated_export_size}GB')
            c.label(text=f'预估时间:\t{pref.estimated_export_time}秒')

    @staticmethod
    def draw_render_export_bottom(layout: 'bpy.types.UILayout'):
        """绘制渲染导出的按钮
        如果不是资产模式就显示"""
        pref = prefs()
        if not pref.is_asset_mode:
            bl_idname = render.ExportRenderFile.bl_idname
            row = layout.row(align=True)
            row.scale_y = 1.5
            row.enabled = pref.allow_add_queue
            row.operator(bl_idname, text='添加到渲染队列')

    @staticmethod
    def draw_export_layout(layout: 'bpy.types.UILayout'):
        """绘制导出层
        一个按钮和导出的信息"""
        Queue.draw_render_export_bottom(layout)
        Queue.draw_queue_left_export_info(layout)


class Left:
    layout: 'bpy.types.UILayout'

    # 绘制左边层
    def left_layout(self):
        pref = prefs()
        if path_is_valid():
            if pref.is_show_preferences:
                AssetLayout.left_preferences(self.layout)
            else:
                AssetLayout.left_draw(self.layout)
        else:  # 路径无效
            self.layout.label(text="请加载资产")

    @staticmethod
    def left_preferences(layout: 'bpy.types.UILayout'):
        """绘制左边的偏好设置"""
        layout.label(text='Render Master')

    @staticmethod
    def left_draw(layout: 'bpy.types.UILayout'):
        """左边的绘制"""
        pref = prefs()
        col = layout.column()
        co = layout.column()
        co.scale_x = 1.3
        co.scale_y = 1.3

        row = col.row(align=True)
        row.prop(pref, 'mode', expand=True)

        ro = col.row(align=True)

        c = ro.column()
        c.scale_x = 0.15
        c.prop(pref, 'show_type', expand=True)

        if (not pref.active_assets) and (not pref.is_pool_mode) and (not pref.is_show_render_queue):
            AssetLayout.load_asset(ro)
            col.separator()
        else:
            AssetLayout.draw_tree_layout(ro)

            AssetLayout.draw_export_layout(layout)

            AssetLayout.draw_select_collect(layout)

            AssetLayout.draw_active_asset(layout)

            AssetLayout.draw_import_asset_layout(layout)

    @staticmethod
    def draw_tree_layout(layout: bpy.types.UILayout):
        """绘制树视图
        """
        idname = AssetTree.bl_idname
        pref = prefs()
        asset_tree = pref.asset_pointer.asset_tree
        tree_name = f'asset_{pref.show_type_}_tree'
        tree_index = f'asset_{pref.show_type_}_index'

        column = layout.column()
        if getattr(asset_tree, tree_name, False):
            '''
            如果有树可以显示的话则显示
            '''
            col = column.column()
            col.template_list(
                idname,
                "",
                asset_tree,
                tree_name,
                asset_tree,
                tree_index,
                rows=10,
            )

    @staticmethod
    def draw_active_asset(layout: bpy.types.UILayout):
        """绘制活动选项的资产项
        """
        pref = prefs()
        ass = pref.find_active_asset_(pref, pref.mode)
        if pref.is_fixed_mode:  # 只有固定模式才显示活动项
            if ass:
                ass.draw_active(layout)
            else:
                layout.label(text=f'未选择活动 {pref.mode}')

    @staticmethod
    def draw_import_asset_layout(layout: bpy.types.UILayout):
        """绘制资产导入层
        """
        pref = prefs()
        if pref.is_asset_mode:
            column = layout.column(align=True)

            fake_icon = icon_two(
                pref.import_use_fake_user ^ 1, 'FAKE')

            if pref.is_show_object:
                # 只有导入物体分预览和直接导入
                column.row(align=True).prop(pref, 'import_mode',
                                            expand=True)

                row = column.row(align=True)

                row.prop(pref, 'import_to_active_collect',
                         toggle=True,
                         icon='OUTLINER_COLLECTION',
                         )

                row.prop(pref, 'import_link',
                         toggle=True,
                         icon='LINK_BLEND',
                         text='',
                         )

                row.prop(pref, 'import_use_fake_user',
                         toggle=True,
                         icon=fake_icon,
                         text='',
                         )

                location_row = row.row(align=True)
                location_row.prop(pref, 'import_to_cursor',
                                  toggle=True,
                                  icon='ORIENTATION_CURSOR',
                                  text='',
                                  )

                ro = location_row.row(align=True)
                ro.enabled = bool(pref.location_box)  # if :  # 有定位box
                ro.prop(pref, 'import_to_location_box',
                        toggle=True,
                        icon='STICKY_UVS_LOC',
                        text='',
                        )
                sub_ro = location_row.row(align=True)
                sub_ro.enabled = pref.import_to_location_box
                sub_ro.prop(pref, 'import_set_parent_form_tag',
                            toggle=True,
                            icon='CON_CHILDOF',
                            text='',
                            )

            elif pref.is_show_scene:
                row = column.row(align=True)
                row.prop(pref,
                         'import_link',
                         toggle=True,
                         icon='LINK_BLEND',
                         )
                row.prop(pref,
                         'import_use_fake_user',
                         toggle=True,
                         icon=fake_icon,
                         text='',
                         )
                column.prop(pref,
                            'import_whole_scene',
                            icon='SCENE_DATA')

    @staticmethod
    def draw_select_collect(layout: 'bpy.types.UILayout'):
        """绘制选择集
        如果选择集的索引值为-1则不使用选择集
        """
        from ..utils.preferences.asset_items import SelectCollectItem

        pref = prefs()
        if pref.is_show_select_collect:
            box = layout.box()
            box.label(text="选择集")

            point = pref.asset_items_pointer_
            index = point.asset_select_collect_index

            row = box.row(align=True)
            col = row.column(align=True)
            col.operator(SelectCollectItem.Add.bl_idname, text='', icon='ADD')
            col.operator(SelectCollectItem.Del.bl_idname,
                         text='', icon='PANEL_CLOSE').index = index
            col.active = index != -1
            row.template_list(
                SelectedSet.bl_idname,
                '',
                point,
                'asset_select_collect',
                point,
                'asset_select_collect_index'
            )

    @classmethod
    def draw_out_file_path(cls, layout: "bpy.types.UiLayout"):
        """绘制输出文件的路径
        路径需要是绝对路径,如果不是的话报红
        """

        ren = bpy.context.scene.render
        path = ren.filepath
        is_dir = os.path.isdir(path)
        is_abs = os.path.isabs(path)
        is_tmp = path == "/tmp\\"  # 是临时目录
        path_valid = is_dir and is_abs and not is_tmp  # 是文件夹并且是绝对路径

        lay = layout.row()
        lay.alert = not path_valid

        if not path_valid:
            lay = lay.box()
            lay.label(text="请选择一个绝对路径文件夹")
            lay.label(text="相对路径无法自动将文件加载到渲染队列")
        lay.prop(ren, 'filepath', text='输出文件路径')


class Right:
    layout: 'bpy.types.UILayout'

    # 绘制右边层
    def right_layout(self: bpy.types.Panel, context: bpy.context):
        pref = prefs()
        layout = self.layout
        if path_is_valid():
            if pref.is_show_preferences:
                AddonProperty.draw_pref(layout)
            else:
                AssetLayout.draw_right_assets(self, layout)
        else:  # 没有选择路径
            draw_path(self.layout)

    @staticmethod
    def draw_right_assets(self, layout: 'bpy.types.UILayout'):
        """绘制右则资产"""
        pref = prefs()
        column = layout.column()

        col = column.column()

        if pref.active_assets:
            AssetLayout.draw_assets_items(
                col, [i for i in pref.active_assets if i.is_show])  # 活动项
        else:
            AssetLayout.draw_selected_assets(layout)

    @staticmethod
    def draw_selected_assets(layout: 'bpy.types.UILayout'):
        """绘制已选中资产
        每一个模式选择的不同
        """
        pref = prefs()
        draw_func = getattr(
            AssetLayout, f'draw_selected_{pref.mode.lower()}', None)
        if draw_func:
            draw_func(layout)
        else:
            AssetLayout.load_asset(layout)

    @staticmethod
    def draw_selected_pool(layout: 'bpy.types.UILayout'):
        """绘制已选中了的池"""
        AssetLayout.draw_queue_asset(layout)

    @staticmethod
    def draw_selected_object(layout: 'bpy.types.UILayout'):
        """绘制已选中了的
        物体"""
        pref = prefs()
        items = [i for i in pref.active_scenes if i.selected]
        if items:
            AssetLayout.draw_assets_items(layout, items)  # 已选的物体
        else:
            layout.label(text='未选择场景,请至少选择一个场景')

    @staticmethod
    def draw_selected_scene(layout: 'bpy.types.UILayout'):
        """绘制已选中了的
        场景"""
        pref = prefs()
        items = [i for i in pref.active_objects if i.selected]
        AssetLayout.draw_render_matching_probability(layout)
        if items:
            AssetLayout.draw_assets_items(layout, items)  # 已选的场景
        elif not pref.is_scene_mode:
            layout.label(text='未选择产品,请至少选择一个产品')

    @staticmethod
    def draw_assets_items(layout: 'bpy.types.UILayout', assets_items: 'list'):
        """输入一个资产集合或是可迭代项
        循环绘制资产项"""
        grid_flow = layout.grid_flow(row_major=True)
        for item in assets_items:
            item.draw(grid_flow)

    @staticmethod
    def draw_render_matching_probability(layout: 'bpy.types.UILayout'):
        """绘制场景模式下的匹配渲染项"""
        pref = prefs()
        col = layout.column()
        for obj in pref.location_box_list:
            box = col.box()
            box.label(text=obj.name)
            obj.render_master.draw_render_matching(box)


class AssetLayout(Queue,
                  Left,
                  Right,
                  ):
    """通过更改偏好设置的绘制方法来实现重新绘制偏好设置
    绘制资产层
    """
    layout: 'bpy.types.UILayout'

    @staticmethod
    def render_queue(layout: 'bpy.types.UILayout'):
        pref = prefs()
        if pref.enabled_render_queue:
            layout.operator('wm.render_queue_switch_ui')

    # 左边底部层
    def left_bottom_layout(self: bpy.types.Panel, context: bpy.context):
        """左下角那一小块,只有底栏不显示才会显示
        """
        pref = prefs()
        layout = self.layout

        column = layout.column()
        column.prop(pref, 'icon_size')

        column.prop(pref, 'show_preferences_property',
                    icon='PREFERENCES')

        AssetLayout.render_queue(column)
        column.alert = True
        AssetLayout.exit(layout)

    # 底部绘制层
    def bottom_layout(self: bpy.types.Panel, context: bpy.context):
        pref = prefs()
        layout = self.layout
        layout.prop(pref, 'icon_size')
        layout.prop(pref, 'show_preferences_property', icon='PREFERENCES')
        layout.separator()

        row = layout.row()

        row.prop(pref, 'search_asset_string',
                 text='',
                 icon='VIEWZOOM',
                 )

        ro = row.row(align=True)
        ro.scale_x = 1.5
        AssetLayout.render_queue(row)
        row.operator(SHOW_DOCS.bl_idname)
        AssetLayout.exit(row.row())

    @staticmethod
    def exit(layout: 'bpy.types.UILayout') -> 'bpy.types.UILayout.operator':
        """退出按钮
        """
        from ..ops.render import SwitchRenderUi
        layout.alert = True
        return layout.operator(SwitchRenderUi.bl_idname,
                               text='退出',
                               icon='PANEL_CLOSE'
                               )

    @staticmethod
    def load_asset(layout: 'bpy.types.UILayout') -> 'bpy.types.UILayout.operator':
        """绘制加载资产按钮"""
        op = layout.operator(asset.LoadAsset.bl_idname,
                             icon='FILE_REFRESH',
                             text='加载资产',
                             )
        return op
